package com.jasmine.bjstkserver.server.dict;


import cn.hutool.core.util.StrUtil;
import com.jasmine.auth.util.AuthUtil;
import com.jasmine.bjstkserver.core.config.exception.BjsException;
import com.jasmine.bjstkserver.mapper.DictMapper;
import com.jasmine.core.constants.BjsConstants;
import com.jasmine.core.util.JsonUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 字典
 *
 * @author jasmineXz
 */
@Component
public class DictServiceImpl implements DictService {
    private static final Logger log = LoggerFactory.getLogger(DictServiceImpl.class);

    @Autowired
    private DictMapper dictMapper;

    @Autowired
    private RedisTemplate redisTemplate;


    @Override
    public List<DictEntity> findList(Integer dictId) {
        DictEntity dict = new DictEntity();
        dict.setDictId(dictId);
        return dictMapper.findList(dict);
    }

    @Override
    @Cacheable(cacheNames = "sys_dict",key = "'userId_' + #dict.getUserId() + ':dictId_' + #dict.getDictId()")
    public List<DictEntity> findList(DictEntity dict) {
        return dictMapper.findList(dict);
    }

    @Override
    @CacheEvict(cacheNames = "sys_dict",key = "'userId_' + #dict.getUserId() + ':dictId_' + #dict.getDictId()")
    public Integer updateDict(DictEntity dict) {
        return dictMapper.updateDict(dict);
    }

    /**
     * 字典缓存,以用户ID为key的map类型
     */
    @Override
    public void refreshDictAll() {
        List<DictEntity> list = dictMapper.findList(null);

        Map<Integer, Map<Integer, Map<String, String>>> result = new HashMap<>();

        // 租户ID为KEY,租户下的全部字典集合
        Map<Integer,List<DictEntity>> mapByTenant = list.stream().collect(Collectors.groupingBy(DictEntity::getUserId));

        mapByTenant.forEach((key,value) -> {
            // 租户下的全部父字典
            Map<Integer,List<DictEntity>> dicts = value.stream().collect(Collectors.groupingBy(DictEntity::getDictId));
            Map<Integer,Map<String,String>> parentDicts = new HashMap<>();

            // 字典父ID为key,子ID为集合
            dicts.forEach((dictKey,dictValues) -> {
                Map<String,String> childDicts = new HashMap<>();
                dictValues.forEach(dict -> childDicts.put(dict.getDictCname(),dict.getDictValue()));
                parentDicts.put(dictKey,childDicts);
                redisTemplate.opsForHash().put(
                        BjsConstants.Redis.DICT_USERID + key,
                        String.valueOf(dictKey),
                        JsonUtil.obj2Json(childDicts));
            });
            result.put(key,parentDicts);
        });

        log.info("[BJSTK] 刷新字典");
    }


    @Override
    public HashMap<String, String> getDict(String code, Integer userId) {
        boolean retry = true;
        int retryNum = 0;
        String dictStr = null;
        while (retry && retryNum < 10) {
            dictStr = (String) redisTemplate.opsForHash().get(BjsConstants.Redis.DICT_USERID + userId, code);
            if (StrUtil.isBlank(dictStr)) {
                this.refreshDictAll();
                retryNum ++;
            } else {
                retry = false;
            }
        }
        if (StrUtil.isBlank(dictStr)) {
            throw new BjsException("获取字典失败");
        }
        return JsonUtil.json2Object(dictStr,HashMap.class);
    }


    @Override
    public HashMap<String,String> getDict(String code) {
        return this.getDict(code, AuthUtil.getUserId());
    }


    @Override
    public String getDictValue(String code, String dictName) {
        String dictValue = this.getDict(code).get(dictName);
        Optional.ofNullable(dictValue).orElseThrow(() -> new BjsException("缺少字典配置 : " + code));
        return dictValue;
    }


    @Override
    public String getDictValue(String code, String dictName, Integer userId) {
        String dictValue = this.getDict(code,userId).get(dictName);
        Optional.ofNullable(dictValue).orElseThrow(() -> new BjsException("缺少字典配置 : " + code));
        return dictValue;
    }


}
